
class Point {
  /**
   * 
   * @param {Number} x 
   * @param {Number} y 
   */
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  /**
   * 
   * @param {Point} another_point 
   */
  SquareDistanceTo(another_point) {
    return (this.x - another_point.x) ** 2 + (this.y - another_point.y) ** 2;
  }
}

class Shexian {
  /**
   * 
   * @param {Point} start 
   * @param {Point} end 
   * @param {Number} trajectory_id 用于区分这个射线是从哪条轨迹出来的
   */
  constructor(start, end, trajectory_id = -1) {
    this.start = start;
    this.end = end;
    this.lengthSquare = start.SquareDistanceTo(end);
    this.trajectory_id = trajectory_id;
  }


  /**
   * 
   * @param {Shexian} another_shexian 
   */
  angleTo(another_shexian) {
    let vec1 = [this.end.x - this.start.x, this.end.y - this.start.y];
    let vec2 = [another_shexian.end.x - another_shexian.start.x, another_shexian.end.y - another_shexian.start.y];
    let cos = (vec1[0] * vec2[0] + vec1[1] * vec2[1]) / (Math.sqrt(vec1[0] ** 2 + vec1[1] ** 2) * Math.sqrt(vec2[0] ** 2 + vec2[1] ** 2))
    let cos_2 = (vec1[0] * vec2[0] + vec1[1] * vec2[1]) ** 2 / ((vec1[0] ** 2 + vec1[1] ** 2) * (vec2[0] ** 2 + vec2[1] ** 2));
    let sin_2 = 1 - (cos_2);
    // debugger
    return { cos_square: cos_2, sin_square: sin_2, cos: cos };
  }

  /**
   * 
   * @param {Shexian} another_shexian 
   */
  minEndpointDistanceTo(another_shexian) {
    let d1square = (this.start.x - another_shexian.start.x) ** 2 + (this.start.y - another_shexian.start.y) ** 2;
    let d2square = (this.end.x - another_shexian.end.x) ** 2 + (this.end.y - another_shexian.end.y) ** 2;
    return Math.sqrt(Math.min(d1square, d2square));
  }

  endpointDistanceToV2(another_shexian) {
    let d1square = (this.start.x - another_shexian.start.x) ** 2 + (this.start.y - another_shexian.start.y) ** 2;
    let d2square = (this.end.x - another_shexian.end.x) ** 2 + (this.end.y - another_shexian.end.y) ** 2;
    return {
      d_start: Math.sqrt(d1square),
      d_end: Math.sqrt(d2square),
      d_min: Math.sqrt(Math.min(d1square, d2square))
    }
  }


  /**
   * 
   * @param {Shexian} another_shexian 
   */
  myDistanceTo(another_shexian) {
    let angleDistance = this.angleTo(another_shexian);
    let endpointDistance = this.minEndpointDistanceTo(another_shexian);
    let MAX_ANGLE = Math.PI / 6;
    // let MIN_COS = Math.cos(MAX_ANGLE);
    let MAX_SIN = Math.sin(MAX_ANGLE);
    if (angleDistance.cos < 0) {
      return Infinity;
    }
    let d1 = angleDistance.sin_square / (MAX_SIN ** 2);
    let MAX_DISTANCE = 100 * 100
    if (endpointDistance > MAX_DISTANCE) {
      return Infinity;
    }
    let d2 = endpointDistance / MAX_DISTANCE;
    return d1 * 0.5 + d2 * 0.5;
  }

}

/**
 * 
 * @param {Array<Array<{x:Number,y:Number}>>} trajectories 
 */
Shexian.getShexiansFromTrajectories = (trajectories) => {
  let result = [];
  for (let traj_i = 0; traj_i < trajectories.length; traj_i++) {
    let points = trajectories[traj_i].map(e => new Point(e.x, e.y));
    for (let i = 0; i < points.length - 1; i++) {
      let shexian = new Shexian(points[i], points[i + 1], traj_i);
      result.push(shexian)
    }
  }
  return result;
}



module.exports = {
  Shexian,
  Point
}